using Engine;
using Engine.Graphics;
using Game;
using GameEntitySystem;

namespace SCIENEW {
    public class FluidTankDevice : ModelDevice, IEntityDevice<ComponentFluidTank>, IFluidTransferrerDevice {
        readonly BlockMesh m_upMesh = new();
        readonly BlockMesh m_downMesh = new();
        readonly BlockMesh m_straightMesh = new();

        public FluidTankDevice() : base(
            "FluidTankDevice",
            "Models/FluidTank",
            "Tank_Normal",
            IndustrialModLoader.IETexture,
            Color.White,
            doubleSided: true
        ) {
            Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(m_model.FindMesh("Tank_Up").ParentBone);
            m_upMesh.AppendModelMeshPart(
                m_model.FindMesh("Tank_Up").MeshParts[0],
                boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f),
                false,
                false,
                true,
                false,
                Color.White
            );
            boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(m_model.FindMesh("Tank_Down").ParentBone);
            m_downMesh.AppendModelMeshPart(
                m_model.FindMesh("Tank_Down").MeshParts[0],
                boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f),
                false,
                false,
                true,
                false,
                Color.White
            );
            boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(m_model.FindMesh("Tank_Straight").ParentBone);
            m_straightMesh.AppendModelMeshPart(
                m_model.FindMesh("Tank_Straight").MeshParts[0],
                boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f),
                false,
                false,
                true,
                false,
                Color.White
            );
        }

        public override bool IsTransparent_(int value) => true;

        public override bool IsFaceTransparent(SubsystemTerrain subsystemTerrain, int face, int value) => true;

        public override int GetShadowStrength(int value) => -99;

        public override float GetObjectShadowStrength(int value) => 0;

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z) {
            int upValue = generator.SubsystemTerrain.Terrain.GetCellValueFast(x, y + 1, z);
            int downValue = generator.SubsystemTerrain.Terrain.GetCellValueFast(x, y - 1, z);
            bool up = DevicesBlockManager.GetDevice(upValue) is FluidTankDevice;
            bool down = DevicesBlockManager.GetDevice(downValue) is FluidTankDevice;

            BlockMesh mesh = m_blockMesh;
            if (up && !down) mesh = m_downMesh;
            else if (!up && down) mesh = m_upMesh;
            else if (up && down) mesh = m_straightMesh;
            generator.GenerateShadedMeshVertices(
                BlocksManager.Blocks[BaseDeviceBlock.Index],
                x,
                y,
                z,
                mesh,
                Color.White,
                null,
                null,
                geometry.GetGeometry(m_texture).SubsetAlphaTest
            );
        }

        public override int GetFaceTextureSlot(int face, int value) => 205;

        public string GetEntityName(int value) => "FluidTank";

        public Widget GetWidget(IInventory inventory, ComponentFluidTank component) => new FluidTankWidget(inventory, component);

        public override DeviceBehavior[] GetBehaviors(Project project) => [new FluidTankDeviceBehavior(project), new FluidTransferrerDeviceBehavior(project)];

        public FluidTransferrer? CreateFluidTransferrer(SubsystemFluidTransfer subsystemFluidTransfer, SubsystemTerrain subsystemTerrain, int value, Point3 point) => new FluidTankTransferrer(point, subsystemTerrain);

        public FluidConnector? GetConnector(SubsystemTerrain terrain, int value, int face, int x, int y, int z) => new FluidConnector(new CellFace(x, y, z, face), FluidConnectorType.InputOutput, 16);

        public override bool IsFluidBlocker_(int value) => false;
    }
}